/*
 * File: CustomModel.cs
 * Author: Gourav Das
 * Purpose: Base Model for other models
 * Created: May 18 2011
 */

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Komires.MataliPhysics;

namespace _22yards.ThreeD
{

	public class MeshTag
	{
		public Effect effect;
		public CMaterial LightMaterial = new LightingMaterial();
		public CMaterial TextureMaterial = new TextureMaterial();
		public Vector3 Color;
		public Texture2D Texture;
		public float SpecularPower;
		
		public Effect CachedEffect = null;
		public MeshTag(Vector3 Color, Texture2D Texture, float SpecularPower)
		{
			this.Color = Color;
			this.Texture = Texture;
			this.SpecularPower = SpecularPower;
		}
	}

	/// <summary>
	/// Base class for all models
	/// </summary>
	public class CustomModel
	{
		private VertexPositionColor[] cameraVertices;
		private VertexPositionNormalTexture[] vertices;
		private int vertexcount;
		private BoundingBox boundingBox;
		private bool drawBoundingBoxes = false;
		private bool drawPhysicsObject = false;
		private bool drawModel = true;
		private BasicEffect effectDebugView;
		//private Matrix MyWorldTransform;
		//private RenderTarget2D RenderTarget;
		public Texture2D ShadowMapTexture;
		public string Technique { get; set; }
		public float HeightScale { get; set; }
		//public float DepthBias { get; set; }
		public Matrix lightsViewProjection { get; set; }
		private Matrix localWorld = Matrix.Identity;
		public Matrix World
		{
			get
			{
				return localWorld;
			}
		}
		/// <summary>
		/// Enables/disables the drawing of bounding box of Associated PhysicsObject. 
		/// </summary>
		/// <param name="val">if set to <c>true</c> [val].</param>
		public void EnableDrawBoundingBox(bool val)
		{
			drawBoundingBoxes = val;
		}

		/// <summary>
		/// Enables/disables the drawing physics object mesh of associated physics
		/// </summary>
		/// <param name="val">if set to <c>true</c> [val].</param>
		public void EnableDrawPhysicsObject(bool val)
		{
			drawPhysicsObject = val;
		}

		public void EnableDrawModel(bool val)
		{
			drawModel = val;
		}

		private PhysicsObject physicsObject = null;
		public PhysicsObject PhysicsObject
		{
			get
			{
				return physicsObject;
			}
			set
			{
				physicsObject = value;
				if (value != null)
				{
					vertexcount = PhysicsObject.Shape.VertexCount;
					vertices = new VertexPositionNormalTexture[vertexcount];
				}
			}
		}
		
		private BoundingSphere boundingSphere;
		public BoundingSphere BoundingSphere
		{
			get
			{
				// No need for rotation, as this is a sphere
				Matrix worldTransform = Matrix.CreateScale(Scale)
				* Matrix.CreateTranslation(Position);
				BoundingSphere transformed = boundingSphere;
				transformed = transformed.Transform(worldTransform);
				return transformed;
			}
		}

		private Vector3 rotation = Vector3.Zero;
		public string Name { get; private set; }
		public short ID { get; private set; }

		public Vector3 Position = Vector3.Zero;

		private Matrix rotMatrix = Matrix.Identity;
		public Matrix RotationMatrix
		{
			get
			{
				return rotMatrix;
			}
			protected set
			{
				rotMatrix = value;
			}
		}
		public Vector3 Rotation
		{
			get
			{
				return rotation;
			}
			set
			{
				rotation = value;
				rotMatrix = Matrix.CreateFromYawPitchRoll(rotation.Y, rotation.X, rotation.Z);
			}
		}
		public Vector3 Scale
		{
			get
			{
				return scale;
			}
			set
			{
				scale = value;
			}
		}

		private Vector3 scale = new Vector3(1, 1, 1);

		public Model model { get; private set; }

		protected Matrix[] modelTransforms;
		private GraphicsDevice graphicsDevice;

		/// <summary>
		/// Builds the bounding sphere.
		/// </summary>
		private void buildBoundingSphere()
		{
			BoundingSphere sphere = new BoundingSphere(Vector3.Zero, 0);
			// Merge all the model's built in bounding spheres
			foreach (ModelMesh mesh in model.Meshes)
			{
				BoundingSphere transformed = mesh.BoundingSphere.Transform(modelTransforms[mesh.ParentBone.Index]);
				sphere = BoundingSphere.CreateMerged(sphere, transformed);
			}
			this.boundingSphere = sphere;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="CustomModel"/> class.
		/// </summary>
		/// <param name="_Model">The XNA model.</param>
		/// <param name="_Position">The position.</param>
		/// <param name="_Rotation">The rotation.</param>
		/// <param name="_Scale">The scale factor.</param>
		/// <param name="_graphicsDevice">The graphics device.</param>
		/// <param name="_Name">Name of the Model.</param>
		/// <param name="_ID">The ID of the model.</param>
		public CustomModel(Model _Model, Vector3 _Position, Vector3 _Rotation,
			Vector3 _Scale, ref GraphicsDevice _graphicsDevice, string _Name, short _ID, PhysicsObject _physxEntity= null)
			{
				PhysicsObject = _physxEntity;
				Name = _Name;
				ID = _ID;
				this.model = _Model;
				modelTransforms = new Matrix[_Model.Bones.Count];
				model.CopyAbsoluteBoneTransformsTo(modelTransforms);

				buildBoundingSphere();
				generateTags();

				this.Position = _Position;
				this.Rotation = _Rotation;
				this.Scale = _Scale;
				this.graphicsDevice = _graphicsDevice;
				effectDebugView = new BasicEffect(graphicsDevice);
				cameraVertices = new VertexPositionColor[24];

				//RenderTarget = new RenderTarget2D(graphicsDevice, 2048, 2048, true,
				//graphicsDevice.PresentationParameters.BackBufferFormat,
				//DepthFormat.Depth24Stencil8);
				
			}

		/// <summary>
		/// Store references to all of the model's current effects
		/// </summary>
		public void CacheEffects()
		{
			foreach (ModelMesh mesh in model.Meshes)
				foreach (ModelMeshPart part in mesh.MeshParts)
					((MeshTag)part.Tag).CachedEffect = part.Effect;
		}
		
		/// <summary>
		/// Restore the effects referenced by the model's cache
		/// </summary>
		public void RestoreEffects()
		{
			foreach (ModelMesh mesh in model.Meshes)
				foreach (ModelMeshPart part in mesh.MeshParts)
					if (((MeshTag)part.Tag).CachedEffect != null)
						part.Effect = ((MeshTag)part.Tag).CachedEffect;
		}

		protected void setEffectParameter(Effect _effect, string _ParamName, object _val)
		{
			if (_effect.Parameters[_ParamName] == null)
				throw new NotImplementedException();

			if (_val is Vector3)
			{
				_effect.Parameters[_ParamName].SetValue((Vector3)_val);
			}
			else if (_val is Matrix)
			{
				_effect.Parameters[_ParamName].SetValue((Matrix)_val);
			}
			else if (_val is Texture2D)
			{
				_effect.Parameters[_ParamName].SetValue((Texture2D)_val);
			}
			else if (_val is float)
			{
				_effect.Parameters[_ParamName].SetValue((float)_val);
			}
		}

		/// <summary>
		/// Sets the model effect.
		/// </summary>
		/// <param name="effect">The effect.</param>
		/// <param name="CopyEffect">if set to <c>true</c> [copy effect].</param>
		/// <param name="MeshName">Name of the mesh.</param>
		/// <param name="_Meshtexture">The _ meshtexture.</param>
		public virtual void SetModelMeshEffect(Effect effect, bool CopyEffect, CMaterial _LightingMaterial, string MeshName = "", params Texture2D[] _Meshtexture)
		{
			foreach (ModelMesh mesh in model.Meshes)
			{
				foreach (ModelMeshPart part in mesh.MeshParts)
				{
					Effect toSet = effect;
					// Copy the effect if necessary
					if (CopyEffect)
						toSet = effect.Clone();
					MeshTag tag = ((MeshTag)part.Tag);

					// If this ModelMeshPart has a texture, set it to the effect
					if (_Meshtexture == null || _Meshtexture.Count() < 1 || MeshName == "" || MeshName == string.Empty)
					{
						((TextureMaterial)((MeshTag)part.Tag).TextureMaterial).ColorMapTexture = tag.Texture;
						((MeshTag)part.Tag).LightMaterial = _LightingMaterial;
						part.Effect = toSet;
					}
					else if (MeshName == mesh.Name)
					{
						part.Effect = toSet;
						tag.Texture = _Meshtexture[0];
						((TextureMaterial)((MeshTag)part.Tag).TextureMaterial).ColorMapTexture = _Meshtexture[0];
						((MeshTag)part.Tag).LightMaterial = _LightingMaterial;
						tag.effect = toSet;
						part.Tag = tag;

						if (_Meshtexture.Count() > 1)
						{
							((TextureMaterial)((MeshTag)part.Tag).TextureMaterial).NormalMapTexture = _Meshtexture[1];

							if (_Meshtexture.Count() > 2)
							{
								((TextureMaterial)((MeshTag)part.Tag).TextureMaterial).SpecularMapTexture = _Meshtexture[2];

								if (_Meshtexture.Count() > 3)
								{
									((TextureMaterial)((MeshTag)part.Tag).TextureMaterial).HeightMapTexture = _Meshtexture[3];
								}
							}
						}

					}
				}//End of inner for loop
			}//End of outer for loop
		}


		/// <summary>
		/// Sets the model mesh light material.
		/// </summary>
		/// <param name="MeshName">Name of the mesh.</param>
		/// <param name="material">The Lighting material.</param>
		public void SetModelMeshLightMaterial(string MeshName, CMaterial material)
		{
			foreach (ModelMeshPart meshPart in model.Meshes.First(c => c.Name == MeshName).MeshParts)
				((MeshTag)meshPart.Tag).LightMaterial = material;
		}

		/// <summary>
		/// Sets the model mesh texture material.
		/// </summary>
		/// <param name="MeshName">Name of the mesh.</param>
		/// <param name="material">The Texture material.</param>
		public void SetModelMeshTextureMaterial(string MeshName, CMaterial material)
		{
			foreach (ModelMeshPart meshPart in model.Meshes.First(c => c.Name == MeshName).MeshParts)
				((MeshTag)meshPart.Tag).TextureMaterial = material;
		}

		/// <summary>
		/// Sets the model mesh color map texture material.
		/// </summary>
		/// <param name="MeshName">Name of the mesh.</param>
		/// <param name="_colorMap">The color texture map.</param>
		public void SetModelMeshColorMapTextureMaterial(string MeshName, Texture2D _colorMap)
		{
			foreach (ModelMeshPart meshPart in model.Meshes.First(c => c.Name == MeshName).MeshParts)
				((TextureMaterial)((MeshTag)meshPart.Tag).TextureMaterial).ColorMapTexture = _colorMap;
		}

		/// <summary>
		/// Sets the model mesh relief map texture material.
		/// </summary>
		/// <param name="MeshName">Name of the mesh.</param>
		/// <param name="_ReliefMap">The relief map.</param>
		public void SetModelMeshHeightMapTextureMaterial(string MeshName, Texture2D _HeightMap)
		{
			foreach (ModelMeshPart meshPart in model.Meshes.First(c => c.Name == MeshName).MeshParts)
				((TextureMaterial)((MeshTag)meshPart.Tag).TextureMaterial).HeightMapTexture = _HeightMap;
		}

		/// <summary>
		/// Sets the model mesh normal map texture material.
		/// </summary>
		/// <param name="MeshName">Name of the mesh.</param>
		/// <param name="_NormalMap">The normal map.</param>
		public void SetModelMeshNormalMapTextureMaterial(string MeshName, Texture2D _NormalMap)
		{
			foreach (ModelMeshPart meshPart in model.Meshes.First(c => c.Name == MeshName).MeshParts)
				((TextureMaterial)((MeshTag)meshPart.Tag).TextureMaterial).NormalMapTexture = _NormalMap;
		}

		/// <summary>
		/// Sets the model mesh specular map texture material.
		/// </summary>
		/// <param name="MeshName">Name of the mesh.</param>
		/// <param name="_SPECMap">The Specular map.</param>
		public void SetModelMeshSpecularMapTextureMaterial(string MeshName, Texture2D _SPECMap)
		{
			foreach (ModelMeshPart meshPart in model.Meshes.First(c => c.Name == MeshName).MeshParts)
				((TextureMaterial)((MeshTag)meshPart.Tag).TextureMaterial).NormalMapTexture = _SPECMap;
		}

		private void generateTags()
		{
			foreach (ModelMesh mesh in model.Meshes)
				foreach (ModelMeshPart part in mesh.MeshParts)
					if (part.Effect is BasicEffect)
					{
						BasicEffect effect = (BasicEffect)part.Effect;
						MeshTag tag = new MeshTag(effect.DiffuseColor, effect.Texture, effect.SpecularPower);
						part.Tag = tag;
					}
		}

		/// <summary>
		/// Reset3s the 3D environment.
		/// </summary>
		protected void Reset3DVariable()
		{
			graphicsDevice.BlendState = BlendState.Opaque;
			graphicsDevice.DepthStencilState = DepthStencilState.Default;
			graphicsDevice.RasterizerState = RasterizerState.CullNone;
			graphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
		}

		/// <summary>
		/// Draws the specified camera.
		/// </summary>
		/// <param name="Camera">The camera.</param>
		/// <param name="_ModelWorld">The _ model world.</param>
		public virtual void Draw(BaseCamera Camera, Matrix _ModelWorld, float ShadowDepthBias= 0.0023f)
		{
			Reset3DVariable();
			// Calculate the base transformation by combining
			// translation, rotation, and scaling
			Matrix baseWorld = Matrix.CreateScale(Scale)
			* RotationMatrix
			* Matrix.CreateTranslation(Position);

			Matrix MyWorldTransform = _ModelWorld*baseWorld;

			if (PhysicsObject != null)
			{
				Matrix z = Matrix.Identity;
					
				//Decompose the Transform Matrix from Physics object
				Vector3 CacheScale = Vector3.Zero;
				//Vector3 CachePosition = Vector3.Zero;

				PhysicsObject.MainWorldTransform.GetPosition(ref Position);
				PhysicsObject.MainWorldTransform.GetRotation(ref rotMatrix);
				PhysicsObject.MainWorldTransform.GetScale(ref CacheScale);

				CacheScale = Vector3.Multiply(scale, CacheScale);
					
				//((PhysicsObject)PhysicsObject).MainWorldTransform.GetTransformMatrix(ref z);
					
				z = Matrix.CreateScale(CacheScale) * rotMatrix * Matrix.CreateTranslation(Position);
				MyWorldTransform = _ModelWorld * z;

			}
			if (drawModel)
			{
				foreach (ModelMesh mesh in model.Meshes)
				{
					//Matrix localWorld = Matrix.Identity;
					localWorld = modelTransforms[mesh.ParentBone.Index] * MyWorldTransform;

					Matrix WorldInvTranspose = Matrix.Transpose(localWorld);
					WorldInvTranspose = Matrix.Invert(WorldInvTranspose);
					foreach (ModelMeshPart meshPart in mesh.MeshParts)
					{
						Effect effect = meshPart.Effect;

						if (meshPart.Effect is BasicEffect)
						{
							((BasicEffect)effect).World = localWorld;
							((BasicEffect)effect).View = Camera.ViewMatrix;
							((BasicEffect)effect).Projection = Camera.ProjectionMatrix;
							((BasicEffect)effect).EnableDefaultLighting();
							//mesh.Draw();
						}
						else //If effect is custom effect
						{

							if (Technique == null)
							{
								effect.CurrentTechnique = effect.Techniques[0];
							}
							else
								effect.CurrentTechnique = effect.Techniques[Technique];

							switch (effect.CurrentTechnique.Name)
							{
								case "SimpleEffect":
									setEffectParameter(effect, "World", localWorld);
									setEffectParameter(effect, "View", Camera.ViewMatrix);
									setEffectParameter(effect, "Projection", Camera.ProjectionMatrix);
									setEffectParameter(effect, "CameraPosition", Camera.Position);
									setEffectParameter(effect, "WorldInvTranspose", WorldInvTranspose);
									((MeshTag)meshPart.Tag).LightMaterial.SetEffectParameters(effect);
									((MeshTag)meshPart.Tag).TextureMaterial.SetEffectParameters(effect);
									//mesh.Draw();
									break;

								case "NormalMappingNoShadow":
									setEffectParameter(effect, "World", localWorld);
									setEffectParameter(effect, "View", Camera.ViewMatrix);
									setEffectParameter(effect, "Projection", Camera.ProjectionMatrix);
									setEffectParameter(effect, "CameraPosition", Camera.Position);
									setEffectParameter(effect, "WorldInvTranspose", WorldInvTranspose);
									((MeshTag)meshPart.Tag).LightMaterial.SetEffectParameters(effect);
									((MeshTag)meshPart.Tag).TextureMaterial.SetEffectParameters(effect);
									//meshPart.Effect.CurrentTechnique.Passes[0].Apply();
									//mesh.Draw();
									break;

								case "POMMappingNoShadow":
									setEffectParameter(effect, "World", localWorld);
									setEffectParameter(effect, "View", Camera.ViewMatrix);
									setEffectParameter(effect, "Projection", Camera.ProjectionMatrix);
									setEffectParameter(effect, "CameraPosition", Camera.Position);
									setEffectParameter(effect, "WorldInvTranspose", WorldInvTranspose);
									setEffectParameter(effect, "HeightScale", HeightScale);
									((MeshTag)meshPart.Tag).LightMaterial.SetEffectParameters(effect);
									((MeshTag)meshPart.Tag).TextureMaterial.SetEffectParameters(effect);
									meshPart.Effect.CurrentTechnique.Passes[0].Apply();
									//mesh.Draw();
									break;

								case "NormalMappingWithShadow":
									float xOffset = 0.25f + (0.25f / 4096);
									float yOffset = 0.25f + (0.25f / 4096);
									float xScale = -1.00f;
									float yScale = -1.00f;
 
									//We want to remap [-1,1] clip space to [0,1] texture space
									//Multiplying a projected vector by the following matrix should give us
									//x' = 0.5x + xOffset * w
									//y' = -0.5y + yOffset * w
									//z' = 0
									//w' = w
									Matrix matTex = new Matrix(xScale,      0.0f,      0.0f,    0.0f, //Flip x axis
															   0.0f,        yScale,    0.0f,    0.0f, //Flip y axis
															   0.0f,        0.0f,      0.0f,    0.0f,
															   xOffset,     yOffset,   0.0f,    -1.0f);
									setEffectParameter(effect, "World", localWorld);
									setEffectParameter(effect, "View", Camera.ViewMatrix);
									setEffectParameter(effect, "Projection", Camera.ProjectionMatrix);
									setEffectParameter(effect, "CameraPosition", Camera.Position);
									setEffectParameter(effect, "WorldInvTranspose", WorldInvTranspose);
									setEffectParameter(effect, "ShadowMapTexture", ShadowMapTexture);
									setEffectParameter(effect, "LightViewProjection", lightsViewProjection);
									setEffectParameter(effect, "BiasMatrix", matTex);
									//setEffectParameter(effect, "DepthBias", DepthBias);
									((MeshTag)meshPart.Tag).LightMaterial.SetEffectParameters(effect);
									((MeshTag)meshPart.Tag).TextureMaterial.SetEffectParameters(effect);
									//meshPart.Effect.CurrentTechnique.Passes[0].Apply();
									//mesh.Draw();

									break;

								case "ShadowMap":
									setEffectParameter(effect, "World", localWorld);
									setEffectParameter(effect, "LightViewProjection", lightsViewProjection);
									//meshPart.Effect.CurrentTechnique.Passes[0].Apply();

									//mesh.Draw();
									break;
							} //End of Switch loop
						}
					   
					}
					mesh.Draw();
				}
			}//End of If(drawModel) loop

			if (drawBoundingBoxes && PhysicsObject != null && Camera != null)
				DrawBoundingBoxes(Camera);
			if (drawPhysicsObject && PhysicsObject != null && Camera != null)
				DrawPhysicsMeshObject(Camera);

		}

		/// <summary>
		/// Updates this instance.
		/// </summary>
		public virtual void Update()
		{
			rotMatrix = Matrix.CreateFromYawPitchRoll(rotation.Y, rotation.X, rotation.Z);
		}

		/// <summary>
		/// Draws the physics mesh object.
		/// </summary>
		/// <param name="camera">The camera.</param>
		private void DrawPhysicsMeshObject(BaseCamera camera)
		{
			PhysicsObject.Shape.GetMeshVertices(1, 1, false, false, vertices);
			
			effectDebugView.Projection = camera.ProjectionMatrix;
			effectDebugView.View = camera.ViewMatrix;

			Vector3 __scale;
			Quaternion __quat;
			Vector3 __poas;
			Matrix z=Matrix.Identity;
			PhysicsObject.MainWorldTransform.GetTransformMatrix(ref z);
			z.Decompose(out __scale,out  __quat,out  __poas);
			effectDebugView.World = Matrix.CreateScale(__scale) * Matrix.CreateFromQuaternion(__quat) * Matrix.CreateTranslation(__poas);
			foreach (EffectPass pass in effectDebugView.CurrentTechnique.Passes)
			{
				pass.Apply();
				graphicsDevice.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.LineStrip, vertices, 0, vertexcount-1);
			}
		}

		/// <summary>
		/// Draws the bounding boxes of Physical object associated
		/// </summary>
		/// <param name="camera">The camera.</param>
		private void DrawBoundingBoxes(BaseCamera camera)
		{
			Color diffuseColor = Color.Black;
			Vector3 min, max;

			PhysicsObject.GetBoundingBox(ref boundingBox);
			min = boundingBox.Min;
			max = boundingBox.Max;

			cameraVertices[0].Position.X = min.X;
			cameraVertices[0].Position.Y = min.Y;
			cameraVertices[0].Position.Z = min.Z;
			cameraVertices[0].Color = diffuseColor;

			cameraVertices[1].Position.X = max.X;
			cameraVertices[1].Position.Y = min.Y;
			cameraVertices[1].Position.Z = min.Z;
			cameraVertices[1].Color = diffuseColor;

			cameraVertices[2].Position.X = min.X;
			cameraVertices[2].Position.Y = min.Y;
			cameraVertices[2].Position.Z = min.Z;
			cameraVertices[2].Color = diffuseColor;

			cameraVertices[3].Position.X = min.X;
			cameraVertices[3].Position.Y = max.Y;
			cameraVertices[3].Position.Z = min.Z;
			cameraVertices[3].Color = diffuseColor;

			cameraVertices[4].Position.X = min.X;
			cameraVertices[4].Position.Y = min.Y;
			cameraVertices[4].Position.Z = min.Z;
			cameraVertices[4].Color = diffuseColor;

			cameraVertices[5].Position.X = min.X;
			cameraVertices[5].Position.Y = min.Y;
			cameraVertices[5].Position.Z = max.Z;
			cameraVertices[5].Color = diffuseColor;

			cameraVertices[6].Position.X = max.X;
			cameraVertices[6].Position.Y = max.Y;
			cameraVertices[6].Position.Z = max.Z;
			cameraVertices[6].Color = diffuseColor;

			cameraVertices[7].Position.X = min.X;
			cameraVertices[7].Position.Y = max.Y;
			cameraVertices[7].Position.Z = max.Z;
			cameraVertices[7].Color = diffuseColor;

			cameraVertices[8].Position.X = max.X;
			cameraVertices[8].Position.Y = max.Y;
			cameraVertices[8].Position.Z = max.Z;
			cameraVertices[8].Color = diffuseColor;

			cameraVertices[9].Position.X = max.X;
			cameraVertices[9].Position.Y = min.Y;
			cameraVertices[9].Position.Z = max.Z;
			cameraVertices[9].Color = diffuseColor;

			cameraVertices[10].Position.X = max.X;
			cameraVertices[10].Position.Y = max.Y;
			cameraVertices[10].Position.Z = max.Z;
			cameraVertices[10].Color = diffuseColor;

			cameraVertices[11].Position.X = max.X;
			cameraVertices[11].Position.Y = max.Y;
			cameraVertices[11].Position.Z = min.Z;
			cameraVertices[11].Color = diffuseColor;

			cameraVertices[12].Position.X = min.X;
			cameraVertices[12].Position.Y = max.Y;
			cameraVertices[12].Position.Z = min.Z;
			cameraVertices[12].Color = diffuseColor;

			cameraVertices[13].Position.X = min.X;
			cameraVertices[13].Position.Y = max.Y;
			cameraVertices[13].Position.Z = max.Z;
			cameraVertices[13].Color = diffuseColor;

			cameraVertices[14].Position.X = min.X;
			cameraVertices[14].Position.Y = max.Y;
			cameraVertices[14].Position.Z = min.Z;
			cameraVertices[14].Color = diffuseColor;

			cameraVertices[15].Position.X = max.X;
			cameraVertices[15].Position.Y = max.Y;
			cameraVertices[15].Position.Z = min.Z;
			cameraVertices[15].Color = diffuseColor;

			cameraVertices[16].Position.X = max.X;
			cameraVertices[16].Position.Y = min.Y;
			cameraVertices[16].Position.Z = max.Z;
			cameraVertices[16].Color = diffuseColor;

			cameraVertices[17].Position.X = max.X;
			cameraVertices[17].Position.Y = min.Y;
			cameraVertices[17].Position.Z = min.Z;
			cameraVertices[17].Color = diffuseColor;

			cameraVertices[18].Position.X = max.X;
			cameraVertices[18].Position.Y = min.Y;
			cameraVertices[18].Position.Z = max.Z;
			cameraVertices[18].Color = diffuseColor;

			cameraVertices[19].Position.X = min.X;
			cameraVertices[19].Position.Y = min.Y;
			cameraVertices[19].Position.Z = max.Z;
			cameraVertices[19].Color = diffuseColor;

			cameraVertices[20].Position.X = min.X;
			cameraVertices[20].Position.Y = max.Y;
			cameraVertices[20].Position.Z = max.Z;
			cameraVertices[20].Color = diffuseColor;

			cameraVertices[21].Position.X = min.X;
			cameraVertices[21].Position.Y = min.Y;
			cameraVertices[21].Position.Z = max.Z;
			cameraVertices[21].Color = diffuseColor;

			cameraVertices[22].Position.X = max.X;
			cameraVertices[22].Position.Y = max.Y;
			cameraVertices[22].Position.Z = min.Z;
			cameraVertices[22].Color = diffuseColor;

			cameraVertices[23].Position.X = max.X;
			cameraVertices[23].Position.Y = min.Y;
			cameraVertices[23].Position.Z = min.Z;
			cameraVertices[23].Color = diffuseColor;


			effectDebugView.Projection = camera.ProjectionMatrix;
			effectDebugView.View = camera.ViewMatrix;

			effectDebugView.World = Matrix.Identity;

			foreach (EffectPass pass in effectDebugView.CurrentTechnique.Passes)
			{
				pass.Apply();
				graphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineList, cameraVertices, 0, 12);
			}
		}
	}
}
